from .baseStates import (
    BaseState,
    DataExpectState,
    DynamicDataState,
    ReceiveStringState,
    StructExpectState,
)

from . import encodings

class StateIdle(StructExpectState):
    """State that sits and listens for message-type byte."""

    struct = ("U8", )

    def __call__(self, client, **kwargs):
        if client.getInputBufferSize() < self.getDataSize(client):
            # there is nothing to do.
            client.onIdle()
        return super(StateIdle, self).__call__(client, **kwargs)

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        (_type, ) = client.types.unpack(self.struct, _data)
        if _type == 0:
            # framebuffer update
            _rv = StartFbUpdateState()
        elif _type == 1:
            # SetColourMapEntries
            _rv = SetColMapEntriesState()
        elif _type == 2:
            # bell
            _rv = BellState()
        elif _type == 3:
            # ServerCutText
            _rv = ServerCutTextState()
        else:
            raise Exception("Unknown message type %i." % _type)
        return _rv

class ServerCutTextState(ReceiveStringState):
    """Server has sent 'Me has new text in buffer'"""

    # because this is basically 'receive string with padding'
    # state, this state was split to two
    
    skipFields = ("x", ) * 3
    struct = ("U32", )

    def act(self, client):
        _text = client.recvData(self.getDataSize(client))
        #There is currently no way to transfer text outside the Latin-1
        #character set.
        client.onServerCutText(_text.decode("latin1"))
        return StateIdle()

class BellState(BaseState):

    def act(self, client):
        # no other data (but event code) is sent from server
        client.onBell()
        return StateIdle()

class SetColMapEntriesState(StructExpectState):

    struct = (
        ("", "x"),
        ("first-colour", "U16"),
        ("number-of-colours", "U16"),
    )

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        _mapHead = client.types.unpackDict(self.struct, _data)
        return SetColMapEntriesReceiveColorsState(_mapHead)

class SetColMapEntriesReceiveColorsState(StructExpectState):
    """Read the expected amount of colour entries."""

    _data = None

    singleColourDict = (
        ("red", "U16"),
        ("green", "U16"),
        ("blue", "U16"),
    )

    def __init__(self, header):
        self._data = header.copy()
        self.struct = ("U16", ) * 3 * header["number-of-colours"]

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        _colSize = client.types.calcsize(self.singleColourDict)
        _colours = []
        while _data:
            _colours.append(client.types.unpackDict(
                self.singleColourDict, _data[:_colSize]))
            _data = _data[_colSize:]
        self._data["colours"] = _colours
        client.onSetColourMapEntries(self._data)
        return StateIdle()

class StartFbUpdateState(StructExpectState):

    struct = ("x", "U16")

    def act(self, client):
        _data = client.recvData(self.getDataSize(client))
        (_rectCount, ) = client.types.unpack(self.struct, _data)
        return encodings.getParser(_rectCount, StateIdle())

def getMainState():
    return StateIdle()

# vim: set sts=4 sw=4 et :
